#NoEnv
#SingleInstance force
#Persistent
#NoTrayIcon

SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines, -1
DetectHiddenWindows, On

; Global variables
VERSION := 0.94 ; version number
; CHANGE THIS BELOW IN UPDATE FUNCTION TOO

; Get icon here http://icon-generator.net/

; Dont touch
LoadedScripts  := Object()
SelectedScript := 0
ScriptCounter  := 0
Salt           := false
SplashIsOn     := false
ThisCounterGlo := 0

SetTimer, CheckProcess, 8000 ; Check process's every 10 seconds


; Main GUI

Gui, Font, S10 CDefault Bold, Verdana
Gui, Add, Text, x180 y10 w180 h20 , S.M.A.R.T Manager v%VERSION%
Gui, Font, S7 Italic, Verdana
Gui, Add, Text, x230 y30 w80 h20 , by i3egohan
Gui, Font, , 
Gui, Add, ListView, x12 y340 w520 h130 vLogLV, Information
Gui, Add, Tab2, x12 y50 w520 h280 , Setup||Script Manager
Gui, Add, GroupBox, x32 y90 w490 h120 , Add Script
Gui, Add, Text, x42 y110 w70 h20 , Script Path:
Gui, Add, Edit, x112 y110 w195 h20 vScriptPathEdit ReadOnly, C:\Simba\Scripts\MyScript.simba
Gui, Add, Button, x312 y110 w50 h20 , Browse
Gui, Add, Button, x395 y110 w120 h20 , Add Script
Gui, Add, Text, x42 y270 w120 h20 , Encryption Password:
Gui, Add, Edit, x162 y270 w240 h20 vEncryptionPassword Password, 
Gui, Add, Text, x42 y145 w60 h20 , Username:
Gui, Add, Text, x227 y145 w60 h20 , Password:
Gui, Add, Text, x392 y145 w30 h20 , Pin:
Gui, Add, Edit, x112 y145 w100 h20 vCharacterUsername, 
Gui, Add, Edit, x287 y145 w90 h20 Password vCharacterPassword, 
Gui, Add, Edit, x422 y145 w90 h20 vCharacterPin, 
Gui, Add, Text, x42 y180 w70 h20 , Arguments:
Gui, Add, Edit, x112 y180 w400 h20 vArguments gComingSoon Disabled, 
Gui, Add, GroupBox, x32 y220 w490 h100, Settings
Gui, Add, Text, x42 y244 w70 h20 , Simba Path:
Gui, Add, Edit, x113 y244 w195 h22 vSimbaPath ReadOnly, C:/Simba
Gui, Add, Button, x315 y244 w85 h20 , Choose Path
Gui, Add, Button, x42 y295 w230 h20 , Minimize To Tray
Gui, Add, Button, x280 y295 w230 h20 , Check For Update
Gui, Add, Button, x411 y245 w101 h40 gSaveSettings, Save
Gui, Tab, Script Manager
Gui, Add, Button, x22 y290 w100 h30 Disabled vStartB, Start Script
Gui, Add, Button, x132 y290 w100 h15 Disabled vExitB, Exit Script
Gui, Add, Button, x132 y305 w100 h15 Disabled vRemoveB, Remove Script
Gui, Add, Button, x242 y290 w100 h20 Disabled vHideB gHideShow, Hide Simba/Smart
; Gui, Add, Checkbox, x242 y312 w100 h14 vFailSafe gGoFail Disabled, Enable fail safe ; removed in 0.91
Gui, Add, Button, x242 y310 w100 h17, Properties
Gui, Add, Text, x352 y290 w50 h30 , Priority:
Gui, Add, DropDownList, x402 y290 w100 h80 Disabled vListB gPrioritySet, Low|BelowNormal|Normal||AboveNormal|High|RealTime
Gui, Add, ListView, x22 y80 w500 h200 AltSubmit NoSortHdr -Multi vScriptLV gSelectManageScript, Script|Status|Restarted|Character|Total Runtime|This Runtime
Gui, Show, x635 y205 h487 w554, S.M.A.R.T Manager

Gui, Listview, LogLV
LV_Add("", "Welcome to S.M.A.R.T Manager v" . VERSION)

Gui, Listview, ScriptLV
LV_ModifyCol(1, "AutoHdr")
LV_ModifyCol(2, "AutoHdr")
LV_ModifyCol(3, "AutoHdr")
LV_ModifyCol(4, "AutoHdr")
;LV_ModifyCol()
Gui, Listview, LogLV

Menu, tray, NoStandard 

; Prompt user for key if needed
if(EncryptionCheck())
{
	Gui +OwnDialogs
	InputBox, Salt, Encryption Key Needed, Please enter your encryption key:, HIDE, 350, 150
	if(ErrorLevel = 1)
	{
		MsgBox, 16, You must enter your encryption key!, Please enter your encryption key! If you lost it delete settings.ini file.
		ExitApp
	}
}
GoSub, OnStartup

; Additonal settings GUI
Gui, Settings:+AlwaysOnTop +ToolWindow
Gui, Settings:Add, Edit, x292 y10 w70 h20 Disabled Number vFailSafeTimeRandomBox, 60000
Gui, Settings:Add, Edit, x122 y10 w110 h20 Disabled Number vFailSafeTimeBox, 21600000
Gui, Settings:Add, CheckBox, x12 y90 w270 h20 vForceRestart, Force Restart (keep script running no matter what)
Gui, Settings:Add, CheckBox, x12 y70 w270 h20 vRestartCompileErrors, Restart on compile errors
Gui, Settings:Add, CheckBox, x12 y10 w110 h20 vFailSafeModeBox gFailSafeModeBox, Fail Safe Mode:
Gui, Settings:Add, Text, x242 y10 w50 h20 , +Random:
Gui, Settings:Add, Button, x92 y330 w190 h20 gSettingsSave, Save
Gui, Settings:Add, CheckBox, x12 y110 w240 h20 vAutoDisableGFX, Automatically disable graphics
Gui, Settings: Add, CheckBox, x12 y140 w250 h20 vDetectRandoms gDetectRandomBox, Alert when random detected
Gui, Settings:Add, Checkbox, x272 y140 w80 h20 vPlaySoundOnRandom, Sound Alarm
Gui, Settings:Add, CheckBox, x12 y170 w250 h20 vDetectComplete, Terminate script if successfull
Gui, Settings:Add, GroupBox, x2 y50 w370 h180 , Options
Gui, Settings:Add, GroupBox, x2 y240 w370 h80 , Scheduler
Gui, Settings:Add, CheckBox, x12 y200 w90 h20 vSMARTSliderBox, SMART Slider
Gui, Settings:Add, Slider, x112 y200 w250 h20 vSMARTSlider, 65
Gui, Settings:Add, CheckBox, x12 y260 w100 h20 vSchedulerBox gSchedulerBoxSub, Enable Scheduler
Gui, Settings:Add, Text, x12 y290 w70 h20, Start Script:
Gui, Settings:Add, DateTime, x82 y290 w100 h20 vSchedulerStartTime Disabled, M/d/yy HH:mm 
Gui, Settings:Add, Text, x192 y290 w70 h20 , Stop Script:
Gui, Settings:Add, DateTime, x252 y290 w100 h20 vSchedulerStopTime Disabled, M/d/yy HH:mm
Return


ComingSoon:
Msgbox, 32, Coming soon, This feature will be added soon`, check villavu.com
return


GuiClose:
; Cleanup
;Msgbox, 36, Are you sure you want to exit?, If you exit the currently running simba/smart scripts will be terminated
;IfMsgBox No
	;return
for index, element in LoadedScripts
{
	if(element.ProcessID)
	{
		PIDtmp := element.ProcessID
		Loop, 3
			Process, Close, %PIDtmp%
	}
}
FileRemoveDir, %A_ScriptDir%/TmpScripts, 1 ; remove tmp scripts
ExitApp


ButtonProperties:
Gui +OwnDialogs
Gui, Submit, NoHide
if(SelectedScript = 0)
{
	Msgbox, 32, Select script, Please select a script above first!
	return
}

; Load current settings

if(LoadedScripts[SelectedScript].FailSafe)
{
	GuiControl, Settings:Enabled, FailSafeTimeBox
	GuiControl, Settings:Enabled, FailSafeTimeRandomBox
	thisTime := LoadedScripts[SelectedScript].TimeRestart
	GuiControl, Settings:, FailSafeTime, %thisTime%
	GuiControl, Settings:, FailSafeModeBox, 1 ; tick checkbox
}
else
{
	GuiControl, Settings:Disabled, FailSafeTimeBox
	GuiControl, Settings:Disabled, FailSafeTimeRandomBox
	GuiControl, Settings:, FailSafeModeBox, 0 ; tick checkbox
}

if(LoadedScripts[SelectedScript].DetectRandoms)
{
	GuiControl, Settings:Enabled, PlaySoundOnRandom
	GuiControl, Settings:, DetectRandoms, 1 ; tick checkbox
}
else
{
	GuiControl, Settings:Disabled, PlaySoundOnRandom
	GuiControl, Settings:, DetectRandoms, 0 ; tick checkbox
}

if(LoadedScripts[SelectedScript].ForceRestart)
{
	GuiControl, Settings:, ForceRestart, 1
}
else
{
	GuiControl, Settings:, ForceRestart, 0
}

if(LoadedScripts[SelectedScript].RestartCompileErrors)
{
	GuiControl, Settings:, RestartCompileErrors, 1
}
else
{
	GuiControl, Settings:, RestartCompileErrors, 0
}

if(LoadedScripts[SelectedScript].DisableGraphics)
{
	GuiControl, Settings:, AutoDisableGFX, 1
}
else
{
	GuiControl, Settings:, AutoDisableGFX, 0
}

if(LoadedScripts[SelectedScript].DetectRandoms)
{
	GuiControl, Settings:, DetectRandoms, 1
}
else
{
	GuiControl, Settings:, DetectRandoms, 0
}

if(LoadedScripts[SelectedScript].PlaySoundOnRandom)
{
	GuiControl, Settings:, PlaySoundOnRandom, 1
}
else
{
	GuiControl, Settings:, PlaySoundOnRandom, 0
}

if(LoadedScripts[SelectedScript].DetectComplete)
{
	GuiControl, Settings:, DetectComplete, 1
}
else
{
	GuiControl, Settings:, DetectComplete, 0
}

if(LoadedScripts[SelectedScript].SMARTSlider != -1)
{
	vartmp := LoadedScripts[SelectedScript].SMARTSlider
	GuiControl, Settings:, SMARTSlider, %vartmp%
	GuiControl, Settings:, SMARTSliderBox, 1
}
else
{
	GuiControl, Settings:, SMARTSlider, 65
	GuiControl, Settings:, SMARTSliderBox, 0
}

if(LoadedScripts[SelectedScript].SchedulerStartTime != 0)
{
	GuiControl, Settings:Enabled, SchedulerStartTime
	GuiControl, Settings:Enabled, SchedulerStopTime
	
	tmp1 := LoadedScripts[SelectedScript].SchedulerStartTime
	tmp2 := LoadedScripts[SelectedScript].SchedulerStopTime
	GuiControl, Settings:, SchedulerStartTime, %tmp1%
	GuiControl, Settings:, SchedulerStopTime, %tmp2%
	GuiControl, Settings:, SchedulerBox, 1
}
else
{
	GuiControl, Settings:Disabled, SchedulerStartTime
	GuiControl, Settings:Disabled, SchedulerStopTime
	GuiControl, Settings:, SchedulerBox, 0
}

Gui, Settings:Show, x655 y225 h357 w382, SMARTManager Script Properties
Return


DetectRandomBox:
Gui, Settings:Submit, NoHide
if(DetectRandoms)
{
	GuiControl, Settings:Enabled, PlaySoundOnRandom
}
else
{
	GuiControl, Settings:Disabled, PlaySoundOnRandom
}
return

SchedulerBoxSub:
Gui, Settings:Submit, NoHide
if(SchedulerBox)
{
	GuiControl, Settings:Enabled, SchedulerStartTime
	GuiControl, Settings:Enabled, SchedulerStopTime
}
else
{
	GuiControl, Settings:Disabled, SchedulerStartTime
	GuiControl, Settings:Disabled, SchedulerStopTime
}
return

FailSafeModeBox:
Gui, Settings:Submit, NoHide
if(FailSafeModeBox)
{
	GuiControl, Settings:Enabled, FailSafeTimeBox
	GuiControl, Settings:Enabled, FailSafeTimeRandomBox
}
else
{
	GuiControl, Settings:Disabled, FailSafeTimeBox
	GuiControl, Settings:Disabled, FailSafeTimeRandomBox
}
return


SettingsSave:
Gui, Settings:Submit ; hides gui
; Save settings... temp
if(FailSafeModeBox)
{
	; enable fail safe
	Random, rand, 0, %FailSafeTimeRandomBox%
	LoadedScripts[SelectedScript].TimeRestart := FailSafeTimeBox + rand
	LoadedScripts[SelectedScript].FailSafe    := 1
}
else
{
	; disable
	LoadedScripts[SelectedScript].TimeRestart := 21600000
	LoadedScripts[SelectedScript].FailSafe := 0
}

if(ForceRestart)
{
	; enable force restart
	LoadedScripts[SelectedScript].ForceRestart := 1
}
else
{
	LoadedScripts[SelectedScript].ForceRestart := 0
}

; restart on simba compile errors only
if(RestartCompileErrors)
{
	LoadedScripts[SelectedScript].RestartCompileErrors := 1
}
else
{
	LoadedScripts[SelectedScript].RestartCompileErrors := 0
}

; disable smart gfx option
if(AutoDisableGFX)
{
	LoadedScripts[SelectedScript].DisableGraphics := 1
}
else
{
	LoadedScripts[SelectedScript].DisableGraphics := 0
}

; detect randoms
if(DetectRandoms)
{
	LoadedScripts[SelectedScript].DetectRandoms := 1
}
else
{
	LoadedScripts[SelectedScript].DetectRandoms := 0
}

if(PlaySoundOnRandom)
{
	LoadedScripts[SelectedScript].PlaySoundOnRandom := 1
}
else
{
	LoadedScripts[SelectedScript].PlaySoundOnRandom := 0
}

if(DetectComplete)
{
	LoadedScripts[SelectedScript].DetectComplete := 1
}
else
{
	LoadedScripts[SelectedScript].DetectComplete := 0
}

if(SMARTSliderBox)
{
	LoadedScripts[SelectedScript].SMARTSlider := SMARTSlider
}
else
{
	LoadedScripts[SelectedScript].SMARTSlider := -1
}

if(SchedulerBox)
{
	LoadedScripts[SelectedScript].SchedulerStartTime := SchedulerStartTime
	LoadedScripts[SelectedScript].SchedulerStopTime := SchedulerStopTime
}
else
{
	LoadedScripts[SelectedScript].SchedulerStartTime := 0
	LoadedScripts[SelectedScript].SchedulerStopTime := 0	
}
Return


ButtonRemoveScript:
Gui, Listview, LogLV
LV_Add("", "Removed script")
LV_Modify(LV_GetCount(), "Vis")

Gui, Listview, ScriptLV

LV_Modify(SelectedScript, "", "Removed", "Removed", "Removed", "Removed", "Removed", "Removed")

IniDelete, %A_ScriptDir%/settings.ini, Scripts, %SelectedScript%
;IniWrite, false, %A_ScriptDir%/settings.ini, Scripts, %SelectedScript% ; instead of delete just make it blank
IniDelete, %A_ScriptDir%/settings.ini, Characters, %SelectedScript%
;IniWrite, false, %A_ScriptDir%/settings.ini, Characters, %SelectedScript% ; instead of delete just make it blank

LoadedScripts[SelectedScript].StartButton := "Enabled"
LoadedScripts[SelectedScript].ExitButton := "Disabled"
LoadedScripts[SelectedScript].HideButton  := "Disabled"
LoadedScripts[SelectedScript].ListButton  := "Disabled"


Gui, Listview, LogLV
LV_Add("", "Script removed, It will be removed from the manager completely next time you start the program.")
LV_Modify(LV_GetCount(), "Vis")
return

ButtonBrowse:
Gui, Submit, NoHide

Gui +OwnDialogs
FileSelectFile, tmpScriptPath, 3, , Please select a simba script, Simba Script (*.simba)
GuiControl, , ScriptPathEdit, %tmpScriptPath%

return

ButtonChoosePath:
Gui, Submit, NoHide

Gui +OwnDialogs
FileSelectFolder, tmpSimbaPath, , Select Simba Directory
If(ErrorLevel = 0)
{
	IfExist, %tmpSimbaPath%
	{
		GuiControl, , SimbaPath, %tmpSimbaPath%
		IniWrite, %SimbaPath%, %A_ScriptDir%/settings.ini, Simba, path
	
		Gui, Listview, LogLV
		LV_Add("", "Updated simba path successfully!")
		LV_Modify(LV_GetCount(), "Vis")
	}
	else
	{
		Gui, Listview, LogLV
		LV_Add("", "Incorrect simba path!")
		LV_Modify(LV_GetCount(), "Vis")
		Msgbox, 16, Invalid folder, Please select the valid existing folder where simba is installed!
	}
}
else
{
	Gui, Listview, LogLV
	LV_Add("", "Please specify the folder/path/directory where simba is located!")
	LV_Modify(LV_GetCount(), "Vis")
	Msgbox, 32, You must specify Simba path!, You must specify the directory/folder where Simba is installed!
}
return


ButtonMinimizeToTray:
Gui, Hide
Menu, Tray, Click, 1
Menu, tray, Icon
Menu, tray, NoStandard
Menu, tray, add, Open SMART Manager, MenuHandler  ; Creates a new menu item.
Menu, tray, add

Menu, tray, Default, Open SMART Manager

Menu, tray, add, Exit, GuiClose  ; Creates a new menu item.
return


MenuHandler:
Gui, Show
Menu, tray, NoIcon
return


PrioritySet:
if(SelectedScript = 0)
{
	MsgBox, 32, Select script, Please select a script in the box above`, If none is there goto add script.
	return
}
Gui, Submit, NoHide
thePID := LoadedScripts[SelectedScript].ProcessID

if(thePID)
{
	Gui, Listview, LogLV
	LV_Add("", "Set selected script priority to: " . ListB)
	LV_Modify(LV_GetCount(), "Vis")
	Process, Priority, %thePID%, %ListB%
	LoadedScripts[SelectedScript].Priority := ListB
}
else
{
	Gui, Listview, LogLV
	LV_Add("", "Script is not running! Maybe it crashed or you closed it manually?")
}
return



CheckProcess:
Critical ; important to stop thread from being interrupted
for index, element in LoadedScripts
{
	if(element.StartButton = "Disabled") ; script must be running
	{
		; first update times
		thistime := GetTimeRunning((A_TickCount - element.ThisTime) // 1000) 
		totaltime := GetTimeRunning((A_TickCount - element.TotalTime) // 1000)
		
		Gui, Listview, ScriptLV
		LV_Modify(index, "Col5", totaltime, thistime)
		
		; script is running
		tmpPID := element.ProcessID
		TimeRan := A_TickCount - element.StartTime
		
		ThisTimeMSRan := A_TickCount - element.ThisTime
		
		; make sure windows are grouped, and add any new windows accosiated with process id whilst time under 1 minute.
		if((ThisTimeMSRan > 35000 && ThisTimeMSRan < 100000) && !element.WindowsGroupedFlag) ; window was hidden, hide it
		{
			Loop, 5 ; ensure all windows grouped
			{
				GroupAdd, ScriptNumber%index%, ahk_pid %tmpPID%
				Sleep, 100
			}
			
			/*
			if(element.DisableGraphics && !element.DisabledAlreadyGFX)
			{
				DisableSmartGFX(index)
				element.DisabledAlreadyGFX := 1
			}
			*/
			
			if(LoadedScripts[index].Hidden) ; window was hidden, hide it
			{
				WinHide, ahk_group ScriptNumber%index%	
			}
			
			element.WindowsGroupedFlag := true
		}
		
		ThisCounterGlo++
		
		; Check for random event
		if(DetectRandomEvent(index) && !SplashIsOn && element.DetectRandoms)
		{
			IfNotExist, %A_Temp%/SmartManagerAlarm.wav
				FileInstall, SmartManagerAlarm.wav, %A_Temp%/SmartManagerAlarm.wav, 1
			
			; then alert user
			thescript := element.Path
			theuser   := element.Username
			Progress, zh0 x0 y0 CTRed, A random event was just detected`, If you would like to solve yourself pause simba and do it now.`n`nScript: %thescript%`nUser: %theuser%, SMARTManager Random Event Detected
			SplashIsOn := True
			ThisCounterGlo := 0
			
			if(element.PlaySoundOnRandom)
				SoundPlay, %A_Temp%/SmartManagerAlarm.wav
		}
		
		if(SplashIsOn && (ThisCounterGlo >= 4)) ; show for 30 seconds (3 loops of checkprocess
		{
			SplashIsOn := false
			Progress, Off
			ThisCounterGlo := 0
		}
		
		; Debug code
		;Msgbox, 32, Debug Information, PID ErrorLevel: %ErrorLevel%`nPID: %tmpPID%`n
		; End
		
		; If script was success then dont restart
		if(element.DetectComplete && ScriptWasSuccessfull(index))
		{
			LoadedScripts[index].FailSafe := 0
			Gui, Listview, LogLV
			LV_Add("", "Script was sucessfully executed, Now removing from restarter. Script: !" . element.Path)
			Gui, Listview, ScriptLV
			LV_Modify(index, "Col2", "Finished!")		
		}
		
		; YYYYMMDDHH24MISS 

		StTime := element.SchedulerStartTime
		EnvSub, StTime, %A_Now%
		
		; This stops scripts which are using the scheduler when time is up
		ETime := element.SchedulerStopTime
		EnvSub, ETime, %A_Now%
		if(element.SchedulerStartTime != 0 && ETime < 0)
		{
			Gui, Listview, LogLV
			LV_Add("", "Script scheduler is in effect, Stop date/time has been reached, terminating script...")
			element.FailSafe := 0
			
			Loop, 5
			{
				Process, Close, % element.ProcessID
				Sleep, 500
				if(ErrorLevel)
					break
			}
			Gui, Listview, LogLV
			if(ErrorLevel)
			{
				Gui, Listview, ScriptLV
				LV_Modify(index, "Col2", "Stopped")
				Gui, Listview, LogLV
				
				GuiControl, Enabled, StartB
				GuiControl, Disabled, ExitB
				GuiControl, Disabled, HideB
				GuiControl, DIsabled, ListB
				
				GuiControl, , HideB, Hide Simba/Smart
				
				LoadedScripts[index].StartButton := "Enabled"
				LoadedScripts[index].ExitButton  := "Disabled"
				LoadedScripts[index].HideButton  := "Disabled"
				LoadedScripts[index].ListButton  := "Disabled"
				LoadedScripts[index].ProcessID   := ""
				LoadedScripts[index].RestartTimes := 0
				LoadedScripts[index].HiddenAlready := 0
				
				; Remember settings
				;LoadedScripts[SelectedScript].FailSafe := 0
				;LoadedScripts[SelectedScript].TimeRestart := 21600000
				;LoadedScripts[SelectedScript].RestartCompileErrors := 0
				;LoadedScripts[SelectedScript].ForceRestart := 0
				;LoadedScripts[SelectedScript].DisableGraphics := 0
				;LoadedScripts[SelectedScript].DetectRandoms := 0
				
				LV_Add("", "Successfully terminated script/simba")
				LV_Modify(LV_GetCount(), "Vis")
				
				sid := element.ScriptID . ".simba"
				FileDelete, %A_ScriptDir%/TmpScripts/%sid%
				element.ScriptID := 0
				
				continue ; very important else script will just start up again
			}
		}
		
		Process, Exist, %tmpPID%
		
		; Check if script is running
		if((!ErrorLevel && tmpPID != "") || (element.FailSafe && TimeRan > element.TimeRestart) || (element.ForceRestart && !IsScriptRunning(index) && ThisTimeMSRan > 15000) || (element.RestartCompileErrors && IsCompileError(index) && ThisTimeMSRan > 15000) || (tmpPID = "" && StTime < 1)) 
		{
			thePath := A_ScriptDir . "/" . "TmpScripts/" . element.ScriptID . ".crashed"
			; restart script
			Gui, Listview, LogLV
			
			if((!ErrorLevel && tmpPID != ""))
				LV_Add("", "Detected simba/smart crash.. PID does not exist... Restarting")
			else if(element.FailSafe && TimeRan > element.TimeRestart)
				LV_Add("", "Fail safe time elapsed, Restarting script...")
			else if(element.ForceRestart && !IsScriptRunning(index))
				LV_Add("", "Force restart! Detected script not running restarting..")
			else if(element.RestartCompileErrors && IsCompileError(index))
				LV_Add("", "Detected compile errors, restarting..Please wait...")
			else
				LV_Add("", "Detected either simba crash/close or fail safe time elapsed..Please wait...")
			
			
			
			LV_Modify(LV_GetCount(), "Vis")
			
			; Kill Process
			tmpPID := element.ProcessID
			Process, Exist, %tmpPID%
			if(ErrorLevel && tmpPID != "")
			{ ; only kill if process exist
				Loop, 8
				{
					Process, Close, %tmpPID%
					sleep, 100
				}
			}
			
			FileDelete, %thePath% ; remove place holder
			; Crashed, restart
			scriptPath := LoadedScripts[index].Path
				
			IfNotExist, %A_ScriptDir%/TmpScripts
			FileCreateDir, %A_ScriptDir%/TmpScripts

			Random, Rando, 100000, 9999999
			LoadedScripts[index].ScriptID := Rando
			FileCopy, %scriptPath%, %A_ScriptDir%/TmpScripts/%Rando%.simba

			; add restart code to script
			AddRestartCode(Rando, index, true)
			IniRead, sPath, %A_ScriptDir%/settings.ini, Simba, path
			
			if(LoadedScripts[index].Hidden)
				Run, %sPath%\Simba.exe -o "%A_ScriptDir%\TmpScripts\%Rando%.simba" -r, %sPath%, Hide, tempPID
			else
				Run, %sPath%\Simba.exe -o "%A_ScriptDir%\TmpScripts\%Rando%.simba" -r, %sPath%, Min, tempPID
			
			Gui, Listview, LogLV			
			LV_Add("", "Loading simba..Please wait...:" . LoadedScripts[index].Path)
			LV_Modify(LV_GetCount(), "Vis")
			WinWait, ahk_pid %tempPID%

			LoadedScripts[index].ProcessID := tempPID
			LoadedScripts[index].RestartTimes := LoadedScripts[index].RestartTimes + 1
			LoadedScripts[index].StartTime := A_TickCount
			LoadedScripts[index].ThisTime := A_TickCount
			LoadedScripts[index].WindowsGroupedFlag := False
			
			Gui, Listview, ScriptLV
			LV_Modify(index, "Col3", LoadedScripts[index].RestartTimes)
			
			LoadedScripts[index].HiddenAlready := 0
			if(LoadedScripts[index].Hidden) ; window was hidden, hide it
			{
				Loop, 8 ; ensure all windows grouped
				{
					GroupAdd, ScriptNumber%index%, ahk_pid %tempPID%
					Sleep, 100
				}
				;LoadedScripts[SelectedScript].HiddenAlready := 1 ; only group windows once
				WinHide, ahk_group ScriptNumber%index%	
			}
		}
		
		if(element.ScriptID)
		{
			thePath := A_ScriptDir . "/" . "TmpScripts/" . element.ScriptID . ".crashed"
			IfExist, %thePath%
			{
				; Kill Process
				tmpPID := element.ProcessID
				Loop, 8
				{
					Process, Close, %tmpPID%
					sleep, 100
				}
				
				Gui, Listview, LogLV
				LV_Add("", "Detected client crash.. Restarting simba/smart/script..Please wait..")
				LV_Modify(LV_GetCount(), "Vis")
				
				FileDelete, %thePath% ; remove place holder
				; Crashed, restart
				scriptPath := LoadedScripts[index].Path
				
				IfNotExist, %A_ScriptDir%/TmpScripts
				FileCreateDir, %A_ScriptDir%/TmpScripts

				Random, Rando, 100000, 9999999
				LoadedScripts[index].ScriptID := Rando
				FileCopy, %scriptPath%, %A_ScriptDir%/TmpScripts/%Rando%.simba

				; add restart code to script
				AddRestartCode(Rando, index, true)
				IniRead, sPath, %A_ScriptDir%/settings.ini, Simba, path
				
				if(LoadedScripts[index].Hidden)
					Run, %sPath%\Simba.exe -o "%A_ScriptDir%\TmpScripts\%Rando%.simba" -r, %sPath%, Hide, tempPID
				else	
					Run, %sPath%\Simba.exe -o "%A_ScriptDir%\TmpScripts\%Rando%.simba" -r, %sPath%, Min, tempPID
				
				Gui, Listview, LogLV
				LV_Add("", "Loading simba..Please wait...:" . LoadedScripts[SelectedScript].Path)
				LV_Modify(LV_GetCount(), "Vis")
				WinWait, ahk_pid %tempPID%

				LoadedScripts[index].ProcessID := tempPID
				LoadedScripts[index].RestartTimes := LoadedScripts[index].RestartTimes + 1
				LoadedScripts[index].StartTime := A_TickCount
				LoadedScripts[index].ThisTime := A_TickCount
				LoadedScripts[index].WindowsGroupedFlag := False
				
				Gui, Listview, ScriptLV
				LV_Modify(index, "Col3", LoadedScripts[index].RestartTimes)
				
				LoadedScripts[index].HiddenAlready := 0
				if(LoadedScripts[index].Hidden) ; window was hidden, hide it
				{
					Loop, 8 ; ensure all windows grouped
					{
						GroupAdd, ScriptNumber%index%, ahk_pid %tempPID%
						Sleep, 100
					}
					;LoadedScripts[SelectedScript].HiddenAlready := 1 ; only group windows once
					WinHide, ahk_group ScriptNumber%index%	
				}
			}
		}
	}
}
return


OnStartup:
Gui, ListView, ScriptLV
DidRemove := false
WrongKey  := false

if(Salt = false) ; no encryption? use default
	Salt := "i3e"

IfExist, %A_ScriptDir%/settings.ini
{
	CleanupINI() ; do cleanup first...
	
	IniRead, ScriptCount, %A_ScriptDir%/settings.ini, Scripts, count
	if (ScriptCount = ERROR || ScriptCount = 0)
		Return
	
	Loop, %ScriptCount%
	{
		IniRead, ScriptPath, %A_ScriptDir%/settings.ini, Scripts, %A_Index%
		
		if(ScriptPath = false || ScriptPath = "false")
			continue ; skip loop if path is blank
		
		IfExist, %ScriptPath%
		{
			LoadedScripts.Insert(Object()) ; load scripts
			ScriptCounter++
			LoadedScripts[A_Index].Path := ScriptPath
			
			; Default values
			LoadedScripts[A_Index].StartButton := "Enabled"
			LoadedScripts[A_Index].ExitButton := "Disabled"
			LoadedScripts[A_Index].HideButton  := "Disabled"
			LoadedScripts[A_Index].ListButton  := "Disabled"
			LoadedScripts[A_Index].RestartTimes := 0
			LoadedScripts[A_Index].HiddenAlready := 0
			LoadedScripts[A_Index].StartTime := A_TickCount
			LoadedScripts[A_Index].TimeRestart := 21600000
			LoadedScripts[A_Index].FailSafe    := 0
			LoadedScripts[A_Index].RestartCompileErrors := 0
			LoadedScripts[A_Index].ForceRestart := 0
			LoadedScripts[A_Index].DisableGraphics := 0
			LoadedScripts[A_Index].DetectRandoms := 0
			LoadedScripts[A_Index].PlaySoundOnRandom := 0
			LoadedScripts[A_Index].DetectComplete := 0
			LoadedScripts[A_Index].SchedulerStartTime := 0
			LoadedScripts[A_Index].SchedulerStopTime := 0
			LoadedScripts[A_Index].SMARTSlider := -1
			
			;LoadedScripts[A_Index].Priority := "Normal"
			
			IniRead, CDetails, %A_ScriptDir%/settings.ini, Characters, %A_Index%
			if(CDetails != "ERROR")
			{
				Cleaned := BegoDecrypt(CDetails, Salt) ; decrypt using salt in memory
				
				if(InStr(Cleaned, "***"))
				{
					StringReplace, Cleaned, Cleaned, ***, ``, All
					StringSplit, CArray, Cleaned, ``
					
					if(CArray0 >= 3) ; then pin
						LoadedScripts[A_Index].Pin := CArray3
					else
						LoadedScripts[A_Index].Pin := false
					
					;data := "u: " . CArray1 . "`np:" . CArray2 . "`nd: " . Cleaned . "`ncount: " . CArray0
					;MsgBox % data
					
					LoadedScripts[A_Index].Username := CArray1 ; user
					LoadedScripts[A_Index].Password := CArray2 ; pass
				}
				else
				{
					WrongKey := true
				}
			}
			else
			{
				LoadedScripts[A_Index].Username := false
				LoadedScripts[A_Index].Password := false
				LoadedScripts[A_Index].Pin      := false
			}
			
			if(LoadedScripts[A_Index].Username)
				LV_Add("", ScriptPath, "Idle", "0", LoadedScripts[A_Index].Username, "00:00:00", "00:00:00")
			else
				LV_Add("", ScriptPath, "Idle", "0", "none", "00:00:00", "00:00:00")
		}
		else
		{
			DidRemove := true
			;IniRead, ScriptCount2, %A_ScriptDir%/settings.ini, Scripts, count
			;ScriptCount2-- ; decrease counter
			;IniWrite, %ScriptCount2%, %A_ScriptDir%/settings.ini, Scripts, count
			;IniDelete, %A_ScriptDir%/settings.ini, Scripts, %A_Index% ; remove script from list if not exist
			; NEW
			IniWrite, false, %A_ScriptDir%/settings.ini, Scripts, %A_Index% ; instead of delete just make it blank
			IniWrite, false, %A_ScriptDir%/settings.ini, Characters, %A_Index% ; instead of delete just make it blank
		}
	}
}
IniRead, SimbaPathFile, %A_ScriptDir%/settings.ini, Simba, path
if(SimbaPathFile != "ERROR")
	GuiControl, , SimbaPath, %SimbaPathFile%
if(DidRemove)
	MsgBox, 32, Script removed, One or more of your scripts as been removed because it no longer exists

if(WrongKey)
	Msgbox, 16, Encryption error, You have entered a invalid encryption key`, if your using the character management you will get errors`, restart smart manager and re-enter key

Gui, Listview, ScriptLV
LV_ModifyCol(1, "AutoHdr")
LV_ModifyCol(2, "AutoHdr")
LV_ModifyCol(3, "AutoHdr")
LV_ModifyCol(4, "AutoHdr")
;LV_ModifyCol()
Gui, Listview, LogLV
Return


; DEPRICATED
GoFail:
Gui, Submit, NoHide
if(SelectedScript = 0)
{
	Msgbox, 32, Select script, Please select a script above first!
	return
}
Gui +OwnDialogs
if(FailSafe)
{
	LoadedScripts[SelectedScript].FailSafe := 1
	InputBox, tmpTime, Enter Restart Time, Please enter time in milliseconds when script should restart(default: 6 hours=21600000) to add some random time use 21600000+random(20000), , 300, 180, , , , , 21600000
	
	if(!InStr(tmpTime, "rand"))
	{
		if(RegExMatch(tmpTime, "^\d+$"))
		{
			LoadedScripts[SelectedScript].TimeRestart := tmpTime
		}
		else
		{
			MsgBox, 16, Incorrect, You entered incorrect time! We will use default 6 hour restart!
			LoadedScripts[SelectedScript].TimeRestart := 21600000
		}
	}
	else
	{
		; handle random time
		RegExMatch(tmpTime, "\((.*?)\)", RandV)
		RegExMatch(tmpTime, "^(.*?)\+", TimeV)
		
		Random, rTime, 1, RandV1
		
		RandomTime := TimeV1 + rTime
		;msgbox % RandomTime
		if(RegExMatch(RandomTime, "^\d+$"))
		{
			LoadedScripts[SelectedScript].TimeRestart := RandomTime
		}
		else
		{
			MsgBox, 16, Incorrect, You entered incorrect time! We will use default 6 hour restart!
			LoadedScripts[SelectedScript].TimeRestart := 21600000
		}
	}
}
else
{
	LoadedScripts[SelectedScript].TimeRestart := 21600000
	LoadedScripts[SelectedScript].FailSafe := 0
}
return


SelectManageScript:
if A_GuiEvent = Normal
{
	SelectedScript := A_EventInfo
	
	GuiControl, Enable, FailSafe
	
	if(!LoadedScripts[SelectedScript].StartButton && !LoadedScripts[SelectedScript].ExitButton) ; blank button error
	{
		Gui, Listview, LogLV
		LV_Add("", "Possible error, If buttons when blank please report.")
		return
	}
	
	; Get settings
	GuiControl, % LoadedScripts[SelectedScript].StartButton, StartB
	GuiControl, % LoadedScripts[SelectedScript].ExitButton, ExitB
	GuiControl, % LoadedScripts[SelectedScript].HideButton, HideB
	GuiControl, % LoadedScripts[SelectedScript].ListButton, ListB
	
	if(LoadedScripts[SelectedScript].FailSafe)
	{
		GuiControl, , FailSafe, 1 ; tick checkbox
	}
	else
	{
		GuiControl, , FailSafe, 0 ; untick checkbox
	}
	
	if(LoadedScripts[SelectedScript].StartButton = "Enabled") ; only allow removing when script not active
		GuiControl, Enabled, RemoveB
	else
		GuiControl, Disabled, RemoveB
	
	if(LoadedScripts[SelectedScript].Hidden)
		GuiControl, , HideB, Show Simba/Smart
	else
		GuiControl, , HideB, Hide Simba/Smart
	
	if(LoadedScripts[SelectedScript].Priority)
	{
		if(LoadedScripts[SelectedScript].Priority = "Low")
			GuiControl, , ListB, Low||BelowNormal|Normal|AboveNormal|High|RealTime
		else if(LoadedScripts[SelectedScript].Priority = "BelowNormal")
			GuiControl, , ListB, Low|BelowNormal||Normal|AboveNormal|High|RealTime
		else if(LoadedScripts[SelectedScript].Priority = "Normal")
			GuiControl, , ListB, Low|BelowNormal|Normal||AboveNormal|High|RealTime
		else if(LoadedScripts[SelectedScript].Priority = "AboveNormal")
			GuiControl, , ListB, Low|BelowNormal|Normal|AboveNormal||High|RealTime
		else if(LoadedScripts[SelectedScript].Priority = "High")
			GuiControl, , ListB, Low|BelowNormal|Normal|AboveNormal|High||RealTime
		else if(LoadedScripts[SelectedScript].Priority = "RealTime")
			GuiControl, , ListB, Low|BelowNormal|Normal|AboveNormal|High|RealTime||
	}
	else
	{
		GuiControl, , ListB, Low|BelowNormal|Normal||AboveNormal|High|RealTime
	}
}
Return


ButtonStartScript:
if(SelectedScript = 0)
{
	MsgBox, 32, Select script, Please select a script in the box above`, If none is there goto add script.
	return
}

IfNotExist, % LoadedScripts[SelectedScript].Path
{
	Gui, Listview, LogLV
	LV_Add("", "Could not find script, try again: " . LoadedScripts[SelectedScript].Path)
	LV_Modify(LV_GetCount(), "Vis")
	Msgbox, 16, Script not found!, Please check script path and make sure script exists.
	Return
} 

GuiControl, Disabled, StartB ; disable button now
LoadedScripts[SelectedScript].StartButton := "Disabled" ; update button status

NowTime := SchedulerStartTime
EnvSub, NowTime, %A_Now%
if(LoadedScripts[SelectedScript].SchedulerStartTime && NowTime > 0) ; this is for the sceduler, so script doesnt start right away if not needed
{
	Gui, Listview, LogLV
	LV_Add("", "Simba is running with selected script PID: " . LoadedScripts[SelectedScript].ProcessID)
	LV_Modify(LV_GetCount(), "Vis")
	
	Gui, Listview, ScriptLV
	LV_Modify(SelectedScript, "Col2", "Scheduled..")
	
	; Enable other settings
	GuiControl, Enabled, ExitB ; disable button now
	LoadedScripts[SelectedScript].ExitButton := "Enabled" ; update button status

	GuiControl, Enabled, HideB ; disable button now
	LoadedScripts[SelectedScript].HideButton := "Enabled" ; update button status

	GuiControl, Enabled, ListB ; disable button now
	LoadedScripts[SelectedScript].ListButton := "Enabled" ; update button status
	
	LoadedScripts[SelectedScript].StartTime := A_TickCount
	
	LoadedScripts[SelectedScript].ThisTime   := A_TickCount
	LoadedScripts[SelectedScript].TotalTime  := A_TickCount
	LoadedScripts[SelectedScript].LastRandomText := "i3ezsz912" ; unique placeholder :D
	LoadedScripts[SelectedScript].DisabledAlreadyGFX := 0
	LoadedScripts[SelectedScript].WindowsGroupedFlag := false ; fixes some ugly bugs
	LoadedScripts[SelectedScript].ProcessID := ""
	
	/*
	if(FailSafe = 1)
	{
		; if checkbox selected use fail safe
		LoadedScripts[SelectedScript].FailSafe := 1
	}
	*/
	
	GuiControl, Disabled, RemoveB
	return
}

Gui, Listview, LogLV

IniRead, sPath, %A_ScriptDir%/settings.ini, Simba, path
scriptPath := LoadedScripts[SelectedScript].Path
tempPID := ""

IfNotExist, %A_ScriptDir%/TmpScripts
	FileCreateDir, %A_ScriptDir%/TmpScripts

Random, Rando, 100000, 9999999
LoadedScripts[SelectedScript].ScriptID := Rando
FileCopy, %scriptPath%, %A_ScriptDir%/TmpScripts/%Rando%.simba

; add restart code to script
AddRestartCode(Rando, SelectedScript)

Run, %sPath%\Simba.exe -o "%A_ScriptDir%\TmpScripts\%Rando%.simba" -r, %sPath%, Min, tempPID

Gui, Listview, LogLV
LV_Add("", "Loading simba..Please wait...:" . LoadedScripts[SelectedScript].Path)
LV_Modify(LV_GetCount(), "Vis")
WinWait, ahk_pid %tempPID%

LoadedScripts[SelectedScript].ProcessID := tempPID

if(LoadedScripts[SelectedScript].ProcessID != "")
{
	Gui, Listview, LogLV
	LV_Add("", "Simba is running with selected script PID: " . LoadedScripts[SelectedScript].ProcessID)
	LV_Modify(LV_GetCount(), "Vis")
	
	Gui, Listview, ScriptLV
	LV_Modify(SelectedScript, "Col2", "Running..")
	
	; Enable other settings
	GuiControl, Enabled, ExitB ; disable button now
	LoadedScripts[SelectedScript].ExitButton := "Enabled" ; update button status

	GuiControl, Enabled, HideB ; disable button now
	LoadedScripts[SelectedScript].HideButton := "Enabled" ; update button status

	GuiControl, Enabled, ListB ; disable button now
	LoadedScripts[SelectedScript].ListButton := "Enabled" ; update button status
	
	LoadedScripts[SelectedScript].StartTime := A_TickCount
	
	LoadedScripts[SelectedScript].ThisTime   := A_TickCount
	LoadedScripts[SelectedScript].TotalTime  := A_TickCount
	LoadedScripts[SelectedScript].LastRandomText := "i3ezsz912" ; unique placeholder :D
	LoadedScripts[SelectedScript].DisabledAlreadyGFX := 0
	LoadedScripts[SelectedScript].WindowsGroupedFlag := false ; fixes some ugly bugs
	
	/*
	if(FailSafe = 1)
	{
		; if checkbox selected use fail safe
		LoadedScripts[SelectedScript].FailSafe := 1
	}
	*/
	
	GuiControl, Disabled, RemoveB
}
else ; else failed
{
	LV_Add("", "Failed to lauch script and/or simba, Please run program as Administrator and check your paths exist")
	LV_Modify(LV_GetCount(), "Vis")
	GuiControl, Enabled, StartB ; disable button now
	LoadedScripts[SelectedScript].StartButton := "Enabled" ; update button status
}

return

ButtonAddScript:
Gui, Submit, NoHide

IfNotExist, %A_ScriptDir%/settings.ini
{
	Gui, Listview, LogLV
	LV_Add("", "Please set your valid simba path first in the setup tab!")
	LV_Modify(LV_GetCount(), "Vis")
	Msgbox, 32, Information, Please set your simba path in the settings tab first!
	Return
}

IfNotExist, %ScriptPathEdit%
{
	Gui, Listview, LogLV
	LV_Add("", "Could not find script, try again: " . ScriptPathEdit)
	LV_Modify(LV_GetCount(), "Vis")
	Msgbox, 16, Script not found!, Please check script path and make sure script exists.
	Return
}

if((CharacterUsername && !CharacterPassword) OR (CharacterPassword && !CharacterUsername))
{
	; user set one without the other.
	
	Msgbox, 16, Invalid options, If you want to use character username and password`, You must set both!
}


; Get script count, and add new script, also increment script count
IniRead, ScriptCount, %A_ScriptDir%/settings.ini, Scripts, count ; Get count
if ScriptCount = ERROR ; If no scripts.. add script
	ScriptCount = 1
else
	ScriptCount++
IniWrite, %ScriptCount%, %A_ScriptDir%/settings.ini, Scripts, count ; Update count
IniWrite, %ScriptPathEdit%, %A_ScriptDir%/settings.ini, Scripts, %ScriptCount% ; Add script


; If user set username & password then fill them here
if(StrLen(CharacterUsername) > 1 && StrLen(CharacterPassword) > 1)
{
	if(Salt = false) ; no encryption? use default
			Salt := "i3e"
			
	if(StrLen(CharacterPin) > 2)
		EncryptedData := BegoEncrypt(CharacterUsername . "***" . CharacterPassword . "***" . CharacterPin, Salt) ; pin
	else
		EncryptedData := BegoEncrypt(CharacterUsername . "***" . CharacterPassword, Salt) ; no pin
	
	IniWrite, %EncryptedData%, %A_ScriptDir%/settings.ini, Characters, %ScriptCount%
}

; Clear fields
GuiControl, , CharacterUsername,
GuiControl, , CharacterPassword,
GuiControl, , CharacterPin,

Gui, Listview, LogLV
LV_Add("", "Added script! To start or manage this script goto Script Manager tab")
LV_Modify(LV_GetCount(), "Vis")

Gui, Listview, ScriptLV

; Add script 
LoadedScripts.Insert(Object())
ScriptCounter++

if(StrLen(CharacterUsername) > 1 && StrLen(CharacterPassword) > 1)
{
	LoadedScripts[ScriptCounter].Username := CharacterUsername
	LoadedScripts[ScriptCounter].Password := CharacterPassword
	LoadedScripts[ScriptCounter].Pin := CharacterPin
}
else
{
	LoadedScripts[ScriptCounter].Username := false
	LoadedScripts[ScriptCounter].Password := false
	LoadedScripts[ScriptCounter].Pin := false
}

LoadedScripts[ScriptCounter].Path := ScriptPathEdit
LoadedScripts[ScriptCounter].StartButton := "Enabled"
LoadedScripts[ScriptCounter].ExitButton := "Disabled"
LoadedScripts[ScriptCounter].HideButton  := "Disabled"
LoadedScripts[ScriptCounter].ListButton  := "Disabled"
LoadedScripts[ScriptCounter].RestartTimes := 0
LoadedScripts[ScriptCounter].HiddenAlready := 0
LoadedScripts[ScriptCounter].TimeRestart := 21600000
LoadedScripts[ScriptCounter].RestartCompileErrors := 0
LoadedScripts[ScriptCounter].ForceRestart := 0
LoadedScripts[ScriptCounter].DisableGraphics := 0
LoadedScripts[ScriptCounter].FailSafe := 0
LoadedScripts[ScriptCounter].DetectRandoms := 0
LoadedScripts[ScriptCounter].PlaySoundOnRandom := 0
LoadedScripts[ScriptCounter].DetectComplete := 0
LoadedScripts[ScriptCounter].SchedulerStartTime := 0
LoadedScripts[ScriptCounter].SchedulerStopTime := 0
LoadedScripts[ScriptCounter].SMARTSlider := -1
;LoadedScripts[LoadedScripts._MaxIndex].Priority := "Normal"

if(LoadedScripts[ScriptCounter].Username)
	LV_Add("", ScriptPathEdit, "Idle", "0", LoadedScripts[ScriptCounter].Username, "00:00:00", "00:00:00")
else
	LV_Add("", ScriptPathEdit, "Idle", "0", "none", "00:00:00", "00:00:00")

Gui, Listview, ScriptLV
LV_ModifyCol(1, "AutoHdr")
LV_ModifyCol(2, "AutoHdr")
LV_ModifyCol(3, "AutoHdr")
LV_ModifyCol(4, "AutoHdr")
;LV_ModifyCol()
Gui, Listview, LogLV

return


ButtonExitScript:
if(SelectedScript = 0)
{
	MsgBox, 32, Select script, Please select a script in the box above`, If none is there goto add script.
	return
}
MsgBox, 36, Are you sure?, This will exit the selected script and terminate corresponding Simba process
IfMsgBox Yes
{
	Loop, 5
	{
		Process, Close, % LoadedScripts[SelectedScript].ProcessID
		Sleep, 500
		if(ErrorLevel)
			break
	}
	Gui, Listview, LogLV
	if(ErrorLevel)
	{
		Gui, Listview, ScriptLV
		LV_Modify(SelectedScript, "Col2", "Stopped")
		Gui, Listview, LogLV
		
		GuiControl, Enabled, StartB
		GuiControl, Disabled, ExitB
		GuiControl, Disabled, HideB
		GuiControl, DIsabled, ListB
		
		GuiControl, , HideB, Hide Simba/Smart
		
		LoadedScripts[SelectedScript].StartButton := "Enabled"
		LoadedScripts[SelectedScript].ExitButton  := "Disabled"
		LoadedScripts[SelectedScript].HideButton  := "Disabled"
		LoadedScripts[SelectedScript].ListButton  := "Disabled"
		LoadedScripts[SelectedScript].ProcessID   := ""
		LoadedScripts[SelectedScript].RestartTimes := 0
		LoadedScripts[SelectedScript].HiddenAlready := 0
		
		; Remember settings
		;LoadedScripts[SelectedScript].FailSafe := 0
		;LoadedScripts[SelectedScript].TimeRestart := 21600000
		;LoadedScripts[SelectedScript].RestartCompileErrors := 0
		;LoadedScripts[SelectedScript].ForceRestart := 0
		;LoadedScripts[SelectedScript].DisableGraphics := 0
		;LoadedScripts[SelectedScript].DetectRandoms := 0
		
		LV_Add("", "Successfully terminated script/simba")
		LV_Modify(LV_GetCount(), "Vis")
		
		sid := LoadedScripts[SelectedScript].ScriptID . ".simba"
		FileDelete, %A_ScriptDir%/TmpScripts/%sid%
		LoadedScripts[SelectedScript].ScriptID := 0
	}
	else
	{
		LV_Add("", "There was a problem terminating simba/script, Maybe you already manually closed it?")
		LV_Modify(LV_GetCount(), "Vis")
	}

}
return


HideShow:
if(SelectedScript = 0)
{
	MsgBox, 32, Select script, Please select a script in the box above`, If none is there goto add script.
	return
}

if(!LoadedScripts[SelectedScript].Hidden)
{
	Gui, Listview, ScriptLV
	LV_Modify(SelectedScript, "Col2", "Running *Hidden*")
	
	LoadedScripts[SelectedScript].Hidden := 1
	tempsPID := LoadedScripts[SelectedScript].ProcessID
	
	Gui, Listview, LogLV
	LV_Add("", "Hiding Selected Simba/Smart/Console windows.. Use same button to show them again. PID: " . tempsPID)
	LV_Modify(LV_GetCount(), "Vis")
	
	if(!LoadedScripts[SelectedScript].HiddenAlready) ; if window hide errors make this always true.
	{
		Loop, 8 ; ensure all windows grouped
		{
			GroupAdd, ScriptNumber%SelectedScript%, ahk_pid %tempsPID%
			;Sleep, 100
		}
		LoadedScripts[SelectedScript].HiddenAlready := 1 ; only group windows once
	}
	
	WinHide, ahk_group ScriptNumber%SelectedScript%
	
	GuiControl, , HideB, Show Simba/Smart
}
else
{
	Gui, Listview, ScriptLV
	LV_Modify(SelectedScript, "Col2", "Running..")
	
	Gui, Listview, LogLV
	LV_Add("", "Showing selected Simba/Smart/Console windows. PID: " . tempsPID)
	LV_Modify(LV_GetCount(), "Vis")
	
	LoadedScripts[SelectedScript].Hidden := 0
	tempsPID := LoadedScripts[SelectedScript].ProcessID
	
	Loop, 2
	{
		WinShow, ahk_group ScriptNumber%SelectedScript%
		;Sleep, 100
	}
	
	WinHide, apptitle ; may cause bugs
	WinHide, theAwtToolkitWindow ; may cause bugs
	
	GuiControl, , HideB, Hide Simba/Smart
}
LV_ModifyCol(1, "AutoHdr")
LV_ModifyCol(2, "AutoHdr")
LV_ModifyCol(3, "AutoHdr")
LV_ModifyCol(4, "AutoHdr")
return


SaveSettings:
Gui, Submit, NoHide

if(StrLen(EncryptionPassword) > 1)
{
	IniRead, ScriptCount, %A_ScriptDir%/settings.ini, Scripts, count
	if(ScriptCount > 0 && ScriptCount != "ERROR")
	{
		; warn user current scripts wont work.
		MsgBox, 32, Cannot add encryption key, You have already added scripts`, therefore you cannot add a encryption key... To add one close SMARTManager, and delete settings.ini`, then run the program again and set encryption key first
	}
	else
	{
		IniWrite, yes, %A_ScriptDir%/settings.ini, Encryption, on
		Gui, Listview, LogLV
		LV_Add("", "Encryption key added!")
		LV_Modify(LV_GetCount(), "Vis")
		Salt := EncryptionPassword
	}
}

IfExist, %SimbaPath%
{
	IniWrite, %SimbaPath%, %A_ScriptDir%/settings.ini, Simba, path
	
	Gui, Listview, LogLV
	LV_Add("", "Updated simba path successfully!")
	LV_Modify(LV_GetCount(), "Vis")
}
else
{
	Gui, Listview, LogLV
	LV_Add("", "Path does not exist!, Enter path where simba is located!")
	LV_Modify(LV_GetCount(), "Vis")
	MsgBox, 16, Choose simba path, Please enter a valid path where simba is located
}
Return

AddRestartCode(rand, SelectedScript, AddDefine = false)
{
	global LoadedScripts
	
	theFile := A_ScriptDir . "/TmpScripts/"  . rand . ".simba"
	newFile := ""
	
	flag        := true
	withinlines := 0
	foundarray  := 0
	codestyle   := false
	linecount   := 0
	firstprocedure := true
	gfxflag        := false
	
	crashFile := A_ScriptDir . "\TmpScripts\"  . rand . ".crashed"
	
	; procedure code
	theProcedure .= "// SMARTManager Restarter`n`n"
	theProcedure .= "procedure SMARTManager;`n"
	theProcedure .= "var`n"
	theProcedure .= "  ioPath: string;`n"
	theProcedure .= "  ioFile: Integer;`n"
	theProcedure .= "begin`n"
	theProcedure .= "  ioPath := '" . crashFile . "';`n"
	theProcedure .= "  try`n"
	theProcedure .= "    ioFile := RewriteFile(ioPath, False);`n"
	theProcedure .= "  except`n"
	theProcedure .= "    Writeln('SmartManager Failed!');`n"
	theProcedure .= "  end;`n"
	theProcedure .= "  CloseFile(ioFile);`n"
	theProcedure .= "end;`n"
	
	flagSetup := true
	
	Loop, Read, %theFile%
	{
		if(RegExMatch(A_LoopReadLine, "i)program(.*?);") && flag) ; much better for checking
		{
			flag := false
			
			if(AddDefine)
				newFile .= A_LoopReadLine . "`n`n{$DEFINE SMARTManager}`n{$DEFINE SMARTManagerRestart}`n`n" . theProcedure . "`n`n" ; add the procedure
			else
				newFile .= A_LoopReadLine . "`n`n{$DEFINE SMARTManager}`n`n" . theProcedure . "`n`n" ; add the procedure
		}
		;else if(InStr(A_LoopReadLine, "procedure") && (flag && firstprocedure))
		;{
			;flag := false
			;firstprocedure := false
			;newFile .= "`n" . theProcedure . "`n`n" . A_LoopReadLine ; add the procedure BEFORE
		;}
		else if(InStr(A_LoopReadLine, "SetupSRL;") && flagSetup)
		{
			flagSetup := false
			newFile .= A_LoopReadLine . "`nSRL_Procs[srl_OnRSUpdate] := @SMARTManager; // On rs update call smartmanager restart `n" ; add calling code
			if(LoadedScripts[SelectedScript].DisableGraphics)
				newFile .= "`nSmartSetGraphics(False);`n"
			if(LoadedScripts[SelectedScript].SMARTSlider != -1)
				newFile .= "`nSmartSetRefresh(" . LoadedScripts[SelectedScript].SMARTSlider . ");`n"
		}
		else if(InStr(A_LoopReadLine, "SetupSRL\(\);") && flagSetup)
		{
			flagSetup := false
			newFile .= A_LoopReadLine . "`nSRL_Procs[srl_OnRSUpdate] := @SMARTManager; // On rs update call smartmanager restart `n" ; add calling code
			if(LoadedScripts[SelectedScript].DisableGraphics)
				newFile .= "`nSmartSetGraphics(False);`n"
			if(LoadedScripts[SelectedScript].SMARTSlider != -1)
				newFile .= "`nSmartSetRefresh(" . LoadedScripts[SelectedScript].SMARTSlider . ");`n"
		}
		else if(InStr(A_LoopReadLine, "srl_OnRSUpdate"))
		{
			Gui, Listview, LogLV
			LV_Add("", "Detected SMART crash! Overwritten with SMARTManager successfull")
			LV_Modify(LV_GetCount(), "Vis")
		}
		else if(RegExMatch(A_LoopReadLine, "i)Players\[\d\]\.Name") && LoadedScripts[SelectedScript].Username)
		{
			; fill username method 1
			tmpUser := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Username . "'") ; takes care of username assignment
			newFile .= tmpUser . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)Players\[\d\]\.Pass") && LoadedScripts[SelectedScript].Password)
		{
			; fill password method 1
			tmpPass := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Password . "'") ; takes care of username assignment
			newFile .= tmpPass . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)Players\[\d\]\.Nick") && LoadedScripts[SelectedScript].Username)
		{
			; fill nick method 1
			;Nick := SubStr(LoadedScripts[SelectedScript].Username, -2) ; use last 3 chars of username for nick
			RegExMatch(LoadedScripts[SelectedScript].Username, "([^ -]{3})", Nick)
			
			tmpNick := RegExReplace(A_LoopReadLine, "('.*?')", "'" . Nick . "'") ; takes care of username assignment
			newFile .= tmpNick . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)Players\[\d\]\.Pin") && LoadedScripts[SelectedScript].Pin)
		{
			; fill nick method 1
			tmpPin := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Pin . "'") ; takes care of username assignment
			newFile .= tmpPin . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)With Players\[\d\] Do")) ; deals with handling diffrent coding style
		{
			newFile .= A_LoopReadLine . "`n"
			withinlines := 0
			codestyle := true ; set flag so we know which coding style scripter used
		}
		else if(RegExMatch(A_LoopReadLine, "i)\sName\s") && (codestyle && withinlines < 10) && LoadedScripts[SelectedScript].Username) ; this handles the triker coding style
		{
			; fill username method 2
			tmpUser := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Username . "'") ; takes care of username assignment
			newFile .= tmpUser . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)\sPass\s") && (codestyle && withinlines < 10) && LoadedScripts[SelectedScript].Password) ; this handles the triker coding style
		{
			; fill password method 2
			tmpPass := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Password . "'") ; takes care of username assignment
			newFile .= tmpPass . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)\sNick\s") && (codestyle && withinlines < 10) && LoadedScripts[SelectedScript].Username) ; this handles the triker coding style
		{
			; fill nick method 2
			;Nick := SubStr(LoadedScripts[SelectedScript].Username, -2) ; use last 3 chars of username for nick
			
			RegExMatch(LoadedScripts[SelectedScript].Username, "([^ -]{3})", Nick)
			
			tmpNick := RegExReplace(A_LoopReadLine, "('.*?')", "'" . Nick . "'") ; takes care of username assignment
			newFile .= tmpNick . "`n"
		}
		else if(RegExMatch(A_LoopReadLine, "i)\sPin\s") && (codestyle && withinlines < 10) && LoadedScripts[SelectedScript].Pin) ; this handles the triker coding style
		{
			; fill pin method 2
			tmpPin := RegExReplace(A_LoopReadLine, "('.*?')", "'" . LoadedScripts[SelectedScript].Pin . "'") ; takes care of username assignment
			newFile .= tmpPin . "`n"
		}
		else if(LoadedScripts[SelectedScript].DisableGraphics && RegExMatch(A_LoopReadLine, "i)LoginPlayer"))
		{
				newFile .= A_LoopReadLine . "`nSmartSetGraphics(False);`n"
		}
		else
			newFile .= A_LoopReadLine . "`n" ; build file
		
		if(codestyle)
			withinlines++ ; used for coding style, if within lines is too high we wont replace user details
		
		linecount++
	}
	
	if(flag)
	{
		newFile := "{$DEFINE SMARTManager}`n`n" . theProcedure . "`n`n" . newFile
	}
	
	; define smartmanager
	if(AddDefine = true && flag)
	{
		newFile := "{$DEFINE SMARTManagerRestart}`n`n" . newFile
	}
	
	FileDelete, %theFile%
	FileAppend, %newFile%, %theFile%
}


BegoEncrypt(Data,Pass) 
{
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*2)
   Loop 256
      a := A_Index - 1
     ,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
     ,sBox%a% := a
   Loop 256
      a := A_Index - 1
     ,b := b + sBox%a% + Key%a%  & 255
     ,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
   Loop Parse, Data
      i := A_Index & 255
     ,j := sBox%i% + j  & 255
     ,k := sBox%i% + sBox%j%  & 255
     ,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
     ,Result .= SubStr(Asc(A_LoopField)^sBox%k%, -1, 2)
   StringReplace Result, Result, x, 0, All
   SetFormat Integer, %Format%
   Return Result
}


BegoDecrypt(Data,Pass) 
{
   b := 0, j := 0, x := "0x"
   VarSetCapacity(Result,StrLen(Data)//2)
   Loop 256
      a := A_Index - 1
     ,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
     ,sBox%a% := a
   Loop 256
      a := A_Index - 1
     ,b := b + sBox%a% + Key%a%  & 255
     ,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
   Loop % StrLen(Data)//2
      i := A_Index  & 255
     ,j := sBox%i% + j  & 255
     ,k := sBox%i% + sBox%j%  & 255
     ,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
     ,Result .= Chr((x . SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
   Return Result
}

GetTimeRunningOLD(time)
{
	time    := round(time / 1000)
	seconds := round(mod(time, 60))
	minutes := round(mod(time, 3600) / 60)
	hours   := round(time / 36000)
	
	return hours . "h:" . minutes . "m"
}

GetTimeRunning(Sec) 
{
   OldFormat := A_FormatFloat
   SetFormat, Float, 02.0
   Hrs  := Sec//3600/1
   Min := Mod(Sec//60, 60)/1
   Sec := Mod(Sec,60)/1
   SetFormat, Float, %OldFormat%
   ;Return (Hrs ? Hrs ":" : "") Min ":" Sec
   Return Hrs . ":" . Min . ":" . Sec
}

EncryptionCheck()
{
	global Salt, RUNNING

	IniRead, Enc, %A_ScriptDir%/settings.ini, Encryption, on
	if(Enc = "yes")
	{
		return True
	}
	else
	{
		return False
	}
}


CleanupINI()
{
	; fixes removed scripts on restart
	IniRead, tmpC, %A_ScriptDir%/settings.ini, Scripts, count
	
	if(tmpC = 0 || tmpC = "ERROR" || FileExist(A_ScriptDir . "/settings.ini") = "")
		return
	
	TempStore := Object() ; temp storage for sorting
	CharStore := Object()
	
	Loop, %tmpC%
	{
		IniRead, tmp, %A_ScriptDir%/settings.ini, Scripts, %A_Index%
		IniRead, tmpChar, %A_ScriptDir%/settings.ini, Characters, %A_Index%
		
		IfExist, %tmp% ; skip non existent files..
		{
			TempStore.Insert(tmp) ; store script path temporarly
			CharStore.Insert(tmpChar) ; may have encryption issues here?
		}
		
		IniDelete, %A_ScriptDir%/settings.ini, Scripts, %A_Index%
		IniDelete, %A_ScriptDir%/settings.ini, Characters, %A_Index%
	}
	
	last := 0
	
	; rebuild file, SORTED
	for index, element in TempStore
	{
		if(element != "ERROR")
		{
			if(CharStore[index] != "ERROR" && CharStore[index] != "")
			{
				; must have char stored too...
				IniWrite, %element%, %A_ScriptDir%/settings.ini, Scripts, %A_Index%
				val := CharStore[index]
				IniWrite, %val%, %A_ScriptDir%/settings.ini, Characters, %A_Index%
			}
			else
			{
				; no characters...
				IniWrite, %element%, %A_ScriptDir%/settings.ini, Scripts, %A_Index%
			}
		}
		last := A_Index ; store last
	}
	
	IniWrite, %last%, %A_ScriptDir%/settings.ini, Scripts, count
}


ButtonCheckForUpdate:
URLDownloadToFile, http://smart-manager.googlecode.com/files/Version.ini, %A_ScriptDir%/SMUpdater.ini
IniRead, latestVersion, %A_ScriptDir%/SMUpdater.ini, Info, Version
if(latestVersion > VERSION)
{
	IniRead, dlURL, %A_ScriptDir%/SMUpdater.ini, Info, URL
	Msgbox, 36, Update Available!, There is a newer version of SMARTManager available! Would you like to download version %latestVersion%?
	IfMsgBox, Yes
	{
		Msgbox, Download Starting, Click ok the begin downloading the new version`, It may take a moment so wait until another message appears.
		URLDownloadToFile, %dlURL%, %A_ScriptDir%/SMARTManager%latestVersion%.exe
		Msgbox, 32, Download complete!, Please close smart manager and delete this version`, Then run SMARTManager%latestVersion%.exe which is in the same folder.
	}
}
else
{
	Msgbox, 32, You are running the latest version, There are no updates available!
}
FileDelete, %A_ScriptDir%/SMUpdater.ini
return


GetScriptDebug(index)
{
	ControlGetText, sEditTxt, Edit2, Simba ahk_group ScriptNumber%index%
	Return sEditTxt
}


IsScriptRunning(index)
{
	Global LoadedScripts
	StatusBarGetText, sBarText, 1, Simba ahk_group ScriptNumber%index% ; , msctls_statusbar321, Simba
	if(InStr(sBarText, "Done") || InStr(sBarText, "Stopped") || InStr(sBarText, "Stopping"))
	{
		if(!RegExMatch(GetScriptDebug(index), "i)RANDOM SOLVING FAILED|RANDOM EVENT FAILED|SOLVER FAILED|Failed Random"))
		{
			Gui, Listview, LogLV
			LV_Add("", "Force Restart: Script not running, Re-Running")
			return false
		}
		else
		{
			; make sure script doesnt start again
			LoadedScripts[index].FailSafe := 0
			Gui, Listview, LogLV
			LV_Add("", "Random event solver failed! Disabling script from restarting!")
			Gui, Listview, ScriptLV
			LV_Modify(index, "Col2", "Failed Random Event")
		}
	}
	return true
}


IsCompileError(index)
{
	if(RegExMatch(GetScriptDebug(index), "i)Exception in Script|Compiling failed|ERROR in")) ;InStr(GetScriptDebug(index), "Compiling failed"))
	{
		Gui, Listview, LogLV
		LV_Add("", "Simba compiling error detected! Restarting...IF THIS KEEPS OCCURING FIX THE SCRIPT!!")
		return true
	}
	else	
		return false
}

DisableSmartGFX(index)
{
	; Public SMARTv6.9 - SMART Minimizing Autoing Resource Thing - By BenLand100
	; ahk_class SunAwtFrame
	SetControlDelay, -1
	ControlClick, X408 Y555, Public SMART ahk_group ScriptNumber%index%,,,, NA
}


DetectRandomEvent(index)
{
	GLobal LoadedScripts
	
	dbgText := GetScriptDebug(index)
	TenLines := Object()
	i := 0
	Loop, Parse, dbgText, `n, `r
	{
		if(i >= 10)
			i := 0
		TenLines[i] := A_LoopField
		i++
	}
	i := 0
	Loop, 10
	{
		; Msgbox % TenLines[i]
		if(RegExMatch(TenLines[i], "i)Found Random") && LoadedScripts[index].LastRandomText != TenLines[i]) ; if same random occurs twice in a row whilst lines that seperate them are below 10 this will fail
		{
			LoadedScripts[index].LastRandomText := TenLines[i] ; ensures we dont keep displaying random alert for same txt
			return true
		}
		i++
	}
	return false
}

ScriptWasSuccessfull(index)
{
	GLobal LoadedScripts
	
	dbgText := GetScriptDebug(index)
	TenLines := Object()
	i := 0
	Loop, Parse, dbgText, `n, `r
	{
		if(i >= 3)
			i := 0
		TenLines[i] := A_LoopField
		i++
	}
	i := 0
	Loop, 4
	{
		;Msgbox % TenLines[i]
		if(RegExMatch(TenLines[i], "i)Successfully executed")) ; if same random occurs twice in a row whilst lines that seperate them are below 10 this will fail
			return true
		i++
	}
	return false
}
